﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once
#include "IType.h"
#include "LinkLoadResult.h"
#include "LinkStatus.h"
#include "Box3d.h"
#include "GcmpApiDeclaration.h"
#include "DocumentLoadError.h"

namespace gcmp
{
    class IDocument;
    class IElementFilter;
    class ILinkDocumentElement;
    class IDocumentOpenValidator;

    /// \brief 链接的数据来源
    SERIALIZABLE_ENUM_CLASS(LinkDataSourceType)
    {
        UnKnown                     = -1,   /// < 未知来源
        CollaborationRemoteDataset  = 0,    /// < 来源于协同远端工作单元
        CollaborationLocalDataset   = 1,    /// < 来源于可协同的本地单机版
        File                        = 2,    /// < 来源于文件。旧的方式，使用前请联系
    };

    /// \ brief链接文档类型选项
    struct GCMP_MODEL_INTERFACE_EXPORT LinkDocumentTypeOptions
    {
        // a. 通用选项
        LinkDataSourceType DataSourceType = LinkDataSourceType::CollaborationRemoteDataset;     /// < 链接数据来源

        int DatasetVersion = -1;                                                                /// < 版本
                                                                                                ///     1）DataSourceType用File时，为兼容，此选项需要给-1;
                                                                                                ///     2) DataSourceType用CollaborationRemoteDataset时，用于指定工作单元版本;
                                                                                                ///     3) DataSourceType用CollaborationLocalDataset时，-1表示用最新版本，其它非负值指定版本。

        bool InterProfessionalLink = false;                                                     /// < true表示跨专业链接，false表示同专业链接

        // b. 当DataSourceType=CollaborationRemoteDataset时起作用的选项
        std::wstring FilterId;                                                                  /// < 过滤器Id
                                                                                                ///     1）当UsingStandardDataOfElement为false，即链接非标准数据时，不需要过滤器，直接给L""即可;
                                                                                                ///     2）当DataSourceType是非CollaborationRemoteDataset时，该选项无效。

        bool UsingStandardDataOfElement = false;                                                /// < 是否使用标准数据
                                                                                                ///     1) true表示标准数据, false表示非标准数据;
                                                                                                ///     2) 当DataSourceType是非CollaborationRemoteDataset时，该选项无效。

        // c. 当DataSourceType=CollaborationLocalDataset时起作用的选项
        bool IsFilePathRelative = false;                                                        /// < 是否是相对路径
        std::wstring LinkFilePath;                                                              /// < 单机版文件路径
        bool LoadingOnDemand = false;                                                           /// < 是否按需加载，当UsingStandardDataOfElement为false时该选项无效

        /// \brief 构造函数
        ///
        /// 参数说明见单个选项字段注释
        LinkDocumentTypeOptions(int datasetVersion, const std::wstring& filterId, bool usingStandardDataOfElement, bool interProfessionalLink);

        /// \brief 构造函数
        ///
        /// 参数说明见单个选项字段注释
        LinkDocumentTypeOptions(
            LinkDataSourceType dataSourceType,
            int datasetVersion,
            bool interProfessionalLink,
            const std::wstring& filterId,
            bool usingStandardDataOfElement,
            bool isFilePathRelative,
            const std::wstring& linkFilePath,
            bool loadingOnDemand = false
        );
    };

    /// \brief 链接加载选项
    struct LinkLoadOptions
    {
        bool ShouldFollowChangesOfLinkedDocument = true; /// < 参照文档修改后，是否更新
    };

    /// \brief 链接文档加载信息
    struct GCMP_MODEL_INTERFACE_EXPORT DocumentLinkLoadInfo
    {
        DocumentLoadResult documentLoadResult;                                  /// < 文件加载结果
        IDocumentOpenValidator* pDocOpenValidator = nullptr;                     /// < 文档打开验证器，不用的话，可以设置为空
        std::set<std::wstring>* pUnrecognizedAssemblies = nullptr;               /// < 文档打开未识别的模块名称，作为输入返回值，不用的话，可以不设置，默认为空
    };

    /// \brief 链接标准导出选项
    struct GCMP_MODEL_INTERFACE_EXPORT LinkStandardExportOptions
    {
        bool IsExportModelView = false;  ///< 视图数据导出时是否导出链接的视图数据，为true时会把链接类型对应的链接模型对象导出一个单独的视图数据
    };

    /// \brief 链接文档类型接口
    class GCMP_MODEL_INTERFACE_EXPORT ILinkDocumentType : public IType
    {
        DEFINE_CAST_DERIVED(gcmp::ILinkDocumentType, gcmp::IType);
    public:
        /// \brief 创建链接文档类型
        ///
        /// \param pHostDocument 所属文档
        /// \param datasetId 数据集路径。为空表明文档在后面在Load()时由调用者提供
        /// \param options 链接文档类型选项
        /// \param pLinkLoadResult [out] 可选，创建结果，当返回LinkLoadResult::Loaded时表示成功
        /// \return ILinkDocumentType* 创建好的链接文档类型
        static ILinkDocumentType * Create(
            IDocument* pHostDocument,
            const std::wstring& datasetId,
            const LinkDocumentTypeOptions& options,
            LinkLoadResult* pLinkLoadResult = nullptr
        );

        /// \brief 获取文件的链接方式，true表示跨专业链接，false表示同专业链接
        /// \return bool 返回当前链接文件的链接方式，true表示跨专业链接，false表示同专业链接
        virtual bool IsInterProfessionalLink() const = 0;

        /// \brief 当前链接文档是否使用标准数据，true表示使用标准数据，false表示使用非标准数据
        /// \return bool 返回当前链接文档是否使用标准数据，true表示使用标准数据，false表示使用非标准数据
        virtual bool IsUsingStandardDataOfElement() const = 0;

        /// \brief 获取文件类型链接路径，此接口对单机版和本地文件链接有效
        /// \return 文件路径
        virtual const std::wstring& GetLinkFilePath() const = 0;

        /// \brief 文件链接路径是否是相对路径，此接口对单机版和本地文件链接有效
        /// \return bool 是-true;否-false
        virtual bool IsLinkFilePathRelative() const = 0;

        /// \brief 设置本地文件链接是否以相对路径链接,且此接口只对本地文件链接有效
        ///
        /// \param isLinkFilePathRelative 是否是相对路径链接
        /// \return bool 设置成功返回true;失败false
        virtual bool SetIsLinkFilePathRelative(bool isLinkFilePathRelative) = 0;

        /// \brief 此接口只对数据集有效，获取链接标准数据导出选项
        /// \return 链接标准导出选项
        virtual LinkStandardExportOptions GetStandardExportOptions() const = 0;

        /// \brief 此接口只对数据集有效，设置链接标准数据导出选项
        ///
        /// \param option 链接标准数据导出选项
        /// \return bool 设置成功返回true;失败false
        virtual bool SetStandardExportOptions(const LinkStandardExportOptions& option) = 0;

        /// \brief 本地文件指定路径重新链接,且此接口只对本地文件链接有效
        ///
        /// 只有链接文档在卸载状态下才生效，否则返回LinkLoadResult::NeedUnload
        /// \param linkFilePath 本地文件重新链接的路径，需要是绝对路径
        /// \return LinkLoadResult 加载结果
        virtual LinkLoadResult LoadFrom(const std::wstring& linkFilePath) = 0;

        /// \brief 本地文件指定路径重新链接,且此接口只对本地文件链接有效
        ///
        /// 只有链接文档在卸载状态下才生效，否则返回LinkLoadResult::NeedUnload
        /// \param linkFilePath 本地文件重新链接的路径，需要是绝对路径
        /// \param DocumentLinkLoadInfo 链接文档加载信息
        /// \return LinkLoadResult 加载结果
        virtual LinkLoadResult LoadFrom(const std::wstring& linkFilePath, DocumentLinkLoadInfo& documentLinkLoadInfo) = 0;

        /// \brief 获取链接数据集Id
        ///
        /// 基于文件的数据集，返回路径
        /// \return std::wstring 数据集Id
        virtual std::wstring GetLinkDatasetId() const = 0;

        /// \brief 获取链接数据集版本
        ///
        /// \return int 返回数据集版本。基于文件的数据集，文件有更新返回-1，否则返回0。
        virtual int GetLinkDatasetVersion() const = 0;

        /// \brief 设置链接数据集版本(对本地文件无效）
        ///
        /// \param version 将要设置的数据集版本
        /// \return bool 修改成功返回true，否则返回false。
        virtual bool SetLinkDatasetVersion(int version)  = 0;

        /// \brief 获取上一次加载的错误
        /// \return 返回上次加载的错误
        virtual std::string GetLastError() = 0;

        /// \brief 加载链接文档
        /// \return LinkLoadResult 加载结果
        virtual LinkLoadResult Load() = 0;

        /// \brief 加载链接文档
        ///
        /// \param DocumentLinkLoadInfo 链接文档加载信息
        /// \return LinkLoadResult 加载结果
        virtual LinkLoadResult Load(DocumentLinkLoadInfo& documentLinkLoadInfo) = 0;

        /// \brief 加载链接文档
        ///
        /// 不同于不带参数的Load()，此接口不会创建文档，需要调用者准备好参照文档
        ///
        /// \param pLinkedDocument 被链接进来的参照文档
        /// \param linkLoadOptions 链接加载选项
        /// \return LinkLoadResult 加载结果
        virtual LinkLoadResult LoadWithLinkedDocument(
            IDocument * pLinkedDocument,
            const LinkLoadOptions & linkLoadOptions
        ) = 0;

        /// \brief 加载链接文档
        /// \param linkLoadOptions 链接加载选项
        /// \return LinkLoadResult 加载结果
        virtual LinkLoadResult Load(const LinkLoadOptions & linkLoadOptions) = 0;

        /// \brief 更新链接内容到指定版本
        ///
        /// 对链接数据源是文件来说，输入-1以外的值不更新。
        /// \param version 指定版本。-1指示更新到最新。
        /// \return 是否更新成功
        virtual bool Update(int version) = 0;

        /// \brief 卸载链接文档
        /// \param[out] pErrorMessage 如果传入非空，卸载失败时返回错误信息
        /// \return bool 是否卸载成功
        GCMP_OBSOLETE_API(2022/05/01, ILinkDocumentType::UnloadAndCloseLinkedDocument(std::wstring *)) virtual bool Unload(std::wstring * pErrorMessage) = 0;

        /// \brief 卸载被链接的参照文档，同时关闭参照文档
        /// \param[out] pErrorMessage 如果传入非空，卸载失败时返回错误信息
        /// \return bool 是否卸载成功
        virtual bool UnloadAndCloseLinkedDocument(std::wstring * pErrorMessage) = 0;

        /// \brief 卸载被链接的参照文档（仅卸载，不关闭文档）
        /// \param[out] pErrorMessage 如果传入非空，卸载失败时返回错误信息
        /// \return bool 是否卸载成功
        virtual bool UnloadAndDontCloseLinkedDocument(std::wstring * pErrorMessage) = 0;

        /// \brief 是否加载
        /// \return bool true，已加载；false，未加载
        virtual bool IsLoaded() const = 0;

        /// \brief 获取被链接的子文档
        /// \return const IDocument 链接子文档
        virtual const IDocument* GetLinkDocument() const = 0;

        /// \brief 获取被链接的子文档
        /// \return IDocument 链接子文档
        virtual IDocument* GetLinkDocument() = 0;

        /// \brief 获取被链接子文档的包围盒
        /// \return Box3d 链接子文档的包围盒
        virtual Box3d GetBoundingBox() const = 0;

        /// \brief 设置被链接子文档的包围盒
        /// \return 
        virtual void SetBoundingBox(Box3d& box3d) = 0;

        /// \brief 获取链接过滤器
        /// \return const IElementFilter 链接过滤器
        virtual const IElementFilter* GetLinkDocumentElementFilter() const = 0;

        /// \brief 应用指定的过滤器
        /// \param filterId 过滤器Id
        /// \return true:设置成功；false:设置失败；
        virtual bool ApplyDatasetFilter(const std::wstring& filterId) = 0;

        /// \brief 获取此类型对应的链接对象实例
        virtual std::vector<ILinkDocumentElement*> GetLinkDocumentElements() = 0;

        /// \brief 是否可编辑
        /// \return 可编辑-true;不可编辑-false
        virtual bool IsEditable() const = 0;

        /// \brief 设置是否可编辑
        /// \param isEditable 是否可以编辑
        virtual void SetIsEditable(bool isEditable) = 0;

        /// \brief 设置session id
        /// \param session id
        virtual void SetSessionId(const std::string& sessionId) = 0;

        /// \brief 设置链接文档的路径
        ///
        /// \param linkFilePath 链接文档的文件路径，可以是全路径，也可以是相对路径。请结合SetIsLinkFilePathRelative进行设置。
        virtual void SetLinkFilePath(const std::wstring & linkFilePath) = 0;

        /// \brief 获取未成功加载文件的全路径。
        ///
        /// \return 未成功加载的文件全路径
        virtual const std::wstring& GetNonExistentLinkFileFullPath() const = 0;

        /// \brief 设置链接文档的类型
        virtual void SetLinkDataSourceType(LinkDataSourceType dataSourceType) = 0;

        /// \brief 获取链接文档的类型
        ///
        /// \链接文档的类型
        virtual LinkDataSourceType GetLinkDataSourceType() const = 0;
    public:
        /// \brief 获取Implementation Uid
        ///
        /// \return UniIdentity 返回ImplementationUid
        static UniIdentity GetImplementationUid();

        /// \brief 创建链接文档类型
        ///
        /// \param pHostDocument 所属文档
        /// \param datasetId 数据集路径
        /// \param datasetVersion 数据集版本，-1指本地文件链接,且文件的路径必须是绝对路径，否则创建不成功；本地文件链接默认以绝对路径链接。
        /// \param filterId 过滤器Id。链接工作单元，当usingStandardDataOfElement为false，即链接非标准数据时，不需要过滤器，直接给L""即可；链接文件不需要过滤器，直接给L""即可。
        /// \param usingStandardDataOfElement 链接工作单元是否使用标准数据，true表示标准数据，false表示非标准数据；该参数在链接文件时使用不到，直接给false即可。
        /// \return ILinkDocumentType* 创建好的链接文档类型
        GCMP_OBSOLETE_API(2021/03/01,  ILinkDocumentType::Create(IDocument*,const std::wstring&,const LinkDocumentTypeOptions&)) static ILinkDocumentType * Create(IDocument* pHostDocument,const std::wstring& datasetId,int datasetVersion,const std::wstring& filterId,bool usingStandardDataOfElement);

    };
}
